<template>
  <div class="editor-wrapper">
    <!-- 工具栏 -->
    <Toolbar id="toolbar-container" :editor="editorRef" :default-config="toolbarConfig" :mode="mode" />
    <!-- 编辑器 -->
    <Editor id="editor-container" v-model="modelValue" :default-config="editorConfig" :mode="mode"
      @on-change="handleChange" @on-created="handleCreated" />
  </div>
</template>

<script setup lang="ts">
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { MD5, lib } from "crypto-js";

// API 引用
import FileAPI from "@/api/file";

const props = defineProps({
  modelValue: {
    type: [String],
    default: "",
  },
  excludeKeys: {
    type: Array<string>,
    default: [],
  },
});

const emit = defineEmits(["update:modelValue"]);

const modelValue = useVModel(props, "modelValue", emit);

const editorRef = shallowRef(); // 编辑器实例，必须用 shallowRef
const mode = ref("simple"); // 编辑器模式
const toolbarConfig = ref({
  excludeKeys: props.excludeKeys,
}); // 工具条配置
// 编辑器配置
const editorConfig = ref({
  placeholder: "请输入内容...",
  MENU_CONF: {
    uploadImage: {
      // 自定义图片上传
      async customUpload(file: any, insertFn: any) {
        chunkUpload(file).then((res: any) => {
          insertFn(res.url);
        })
      },
    },
  },
});


const chunkUpload = (file: any) => {
  return new Promise((resolve, reject) => {
    FileAPI.chunkReady({ filename: file.name }).then((res: any) => {
      let uk = res.uk;
      chunkFile(file).then((chunkList: any) => {
        let promiseList = [];
        for (let i: any = 0; i < chunkList.length; i++) {
          promiseList.push(
            new Promise((resolve2, reject2) => {
              const formData = new FormData();
              formData.append("file", chunkList[i].content);
              formData.append("uk", uk);
              formData.append("total", chunkList.length);
              formData.append("idx", i + 1);
              formData.append("md5", chunkList[i].md5);

              FileAPI.chunk(formData).then((step2Res: any) => {
                // insertFn(step2Res.url);
                resolve2(step2Res);
              });
            })
          );
        }

        // 上传所有分片
        Promise.all(promiseList)
          .then((resList) => {
            // 上传的结果里面只会有一个请求返回成功

            let resData = null;
            resList.forEach((item: any) => {
              if (item.url !== undefined) {
                resData = item;
              }
            });

            if (resData === null) {
              reject(new Error("返回数据有误"));
            } else {
              resolve(resData);
            }
          })
          .catch((err) => {
            reject(err);
          });
      })
    })
  })
}

/**
     * 对文件进行分片
     * @param {File} file
     */
const chunkFile = (file: any) => {
  // 每片的大小
  let chunkSize = 1 * 1024 * 1024;
  let cnt = Math.ceil(file.size / chunkSize)
  let list: any = {
    length: cnt,
  };
  let pList = [];

  for (let i = 0; i < cnt; i++) {

    pList.push(new Promise<void>((resolve, reject) => {
      let tmp: any = '';
      let start = i * chunkSize;
      let end = Math.min(file.size, start + chunkSize);

      // 切割文件
      tmp = file.slice(start, end);
      let reader = new FileReader();
      reader.onload = function (ev: any) {

        // 每个片里面装的是 base64编码后的内容
        // 去掉 base64,前面的的内容
        let p: any = ev.target.result;
        // 这里因为 onload是异步执行，所以用push()会导致乱序
        list[i] = {
          content: tmp,
          md5: MD5(lib.WordArray.create(p)).toString()
        };
        resolve()
      }
      reader.onerror = function (er) {
        reject(er)
      }
      // reader.readAsDataURL(tmp)
      reader.readAsArrayBuffer(tmp)

    }))

  }

  return new Promise((res, rej) => {
    Promise.all(pList).then(() => {
      res(list)
    })
      .catch(err => {
        rej(err);
      })
  })
}

const handleCreated = (editor: any) => {
  editorRef.value = editor; // 记录 editor 实例，重要！
};

function handleChange(editor: any) {
  modelValue.value = editor.getHtml();
}

// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});
</script>

<style src="@wangeditor/editor/dist/css/style.css"></style>
